package com.sisSaude.daos;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.ResultSet;
import java.util.Vector;

import com.sisSaude.entityBeans.Aluno;
import com.sisSaude.entityBeans.Funcionario;
import com.sisSaude.entityBeans.Usuario;
import com.sisSaude.utils.DataProvider;
import com.sisSaude.utils.SqlFactory;

public class UsuarioDAO extends GenericDAO<Usuario> {

	// fields
	public static String SELECT_BASICA = " SELECT Usuario.*, " +
			                             "        Funcionario.id AS idFuncionario," +
			                             "        Aluno.id AS idAluno " +
                                         " FROM Usuario " + 
                                         " LEFT JOIN Funcionario ON Funcionario.idUsuario = Usuario.id " + 
                                         " LEFT JOIN Aluno ON Aluno.idUsuario = Usuario.id ";
	
	// public methods
	public boolean canDelete(Usuario usuario) {
		DataProvider dataProvider = new DataProvider();
		return dataProvider.canDelete("Usuario", usuario.getId());
	}
	public boolean delete(Usuario usuario) {
		String sql = SqlFactory.getSqlDelete("Usuario", "id");
		DataProvider dataProvider = new DataProvider();
		Vector<Object> params = new Vector<Object>();
		params.add(usuario.getId());
		try {
			dataProvider.execute(sql, params);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		} finally {
			dataProvider.close();
		}
		return true;
	}
	public Usuario get(int id) {
		return null;
	}
	public Usuario get(String nomeDeLogin, String senha) {
		Usuario usuario = null;
		String sql = SELECT_BASICA + " WHERE Usuario.nomeDeLogin = ? " +
    			  				     " AND Usuario.senha = md5(?) "; 
		DataProvider dataProvider = new DataProvider();
		Vector<Object> params = new Vector<Object>();
		params.add(nomeDeLogin);
		params.add(senha);
		try {
			dataProvider.select(sql, params);
			if (dataProvider.next()) {
				usuario = new Usuario();
				loadAttribs(usuario, dataProvider.getResultSet());
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		} finally {
			dataProvider.close();
		}
		return usuario;
		
	}
	public Usuario get(Aluno aluno) {
		Usuario usuario = null;
		String sql = SELECT_BASICA + " WHERE Usuario.id = ? "; 
		DataProvider dataProvider = new DataProvider();
		Vector<Object> params = new Vector<Object>();
		params.add(aluno.getIdUsuario());
		try {
			dataProvider.select(sql, params);
			if (dataProvider.next()) {
				usuario = new Usuario();
				loadAttribs(usuario, dataProvider.getResultSet());
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		} finally {
			dataProvider.close();
		}
		return usuario;	
	}
	public Usuario get(Funcionario funcionario) {
		Usuario usuario = null;
		String sql = SELECT_BASICA + " WHERE Usuario.id = ? "; 
		DataProvider dataProvider = new DataProvider();
		Vector<Object> params = new Vector<Object>();
		params.add(funcionario.getIdUsuario());
		try {
			dataProvider.select(sql, params);
			if (dataProvider.next()) {
				usuario = new Usuario();
				loadAttribs(usuario, dataProvider.getResultSet());
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		} finally {
			dataProvider.close();
		}
		return usuario;	
	}
	public boolean isUnique(Usuario usuario) {
		String sql = " SELECT COUNT(*) " +
				     " FROM Usuario " +
				     " WHERE nomeDeLogin = ? " +
				     " AND id <> ? "; 
		DataProvider dataProvider = new DataProvider();
		Vector<Object> params = new Vector<Object>();
		params.add(usuario.getNomeDeLogin());
		params.add(usuario.getId());
		try {
			return dataProvider.count(sql, params) == 0;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		} finally {
			dataProvider.close();
		}
	}
	public void loadAttribs(Usuario usuario, ResultSet r) {
		try {
			usuario.setId(r.getInt("id"));
			usuario.setNome(r.getString("nome"));
			usuario.setEMail(r.getString("eMail"));
			usuario.setNomeDeLogin(r.getString("nomeDeLogin"));
			usuario.setSenha(r.getString("senha"));
			usuario.setSenhaOriginal(r.getString("senha"));
			usuario.setAtivo(r.getBoolean("ativo"));
			usuario.setIdAluno(r.getInt("idAluno"));
			usuario.setIdFuncionario(r.getInt("idFuncionario"));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// protected methods
	protected boolean insert(Usuario usuario) {
		String sql = SqlFactory.getSqlInsert("Usuario");
		DataProvider dataProvider = new DataProvider();
		Vector<Object> params = new Vector<Object>();
	 	params.add(usuario.getId());
		params.add(usuario.getNome());
	 	params.add(usuario.getEMail());
	 	params.add(usuario.getNomeDeLogin());
	 	params.add(usuario.getSenhaOriginal().equalsIgnoreCase(usuario.getSenha()) ? usuario.getSenha() : MD5(usuario.getSenha()));
	 	params.add(usuario.isAtivo() ? 1 : 0);
		try {
			usuario.setId(dataProvider.insert(sql, params));
			return usuario.getId() > 0;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		} finally {
			dataProvider.close();
		}
	}
	protected boolean update(Usuario usuario) {
		String sql = SqlFactory.getSqlUpdate("Usuario", "Usuario.id");
		DataProvider dataProvider = new DataProvider();
		Vector<Object> params = new Vector<Object>();
		params.add(usuario.getNome());
	 	params.add(usuario.getEMail());
	 	params.add(usuario.getNomeDeLogin());
	 	params.add(usuario.getSenhaOriginal().equalsIgnoreCase(usuario.getSenha()) ? usuario.getSenha() : MD5(usuario.getSenha()));
	 	params.add(usuario.isAtivo() ? 1 : 0);
	 	params.add(usuario.getId());
		try {
			dataProvider.execute(sql, params);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		} finally {
			dataProvider.close();
		}
		return true;
	}
	
	// private methods
	private static String MD5(String senha) {
		MessageDigest md;
		byte[] hashMd5;
		try {
			md = MessageDigest.getInstance("MD5");
			md.update(senha.getBytes());
			hashMd5 = md.digest();
			return stringHexa(hashMd5);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			return null;
		}		
	}
	private static String stringHexa(byte[] bytes) {
	   StringBuilder s = new StringBuilder();
	   for (int i = 0; i < bytes.length; i++) {
	       int parteAlta = ((bytes[i] >> 4) & 0xf) << 4;
	       int parteBaixa = bytes[i] & 0xf;
	       if (parteAlta == 0) s.append('0');
	       s.append(Integer.toHexString(parteAlta | parteBaixa));
	   }
	   return s.toString();
	}
}
